<?php

namespace origin;

/**
 * 验证类
 * @author dece <decezz@qq.com>
 */
class Validate
{
    // 验证规则
    protected $rules = [];
    // 提示信息
    protected $msg = [];
    // 错误信息
    protected $error = '';

    /**
     * 构造
     * @param  array $rules 验证规则
     * @param  array $msg  提示信息
     * @return void
     */
    public function __construct( $rules = [] , $msg = [] )
    {
        $this->rules = array_merge($this->rules, $rules);
        $this->msg   = array_merge($this->msg, $msg);
    }

    /**
     * 添加并查看规则
     * @param  array $rules 验证规则
     * @return array $rules
     */
    public function rules( array $rules = [] )
    {
        $this->rules = array_merge($this->rules, $rules);
        return $this->rules;
    }

    /**
     * 添加提示信息并查看提示信息
     * @param  array $msg 提示信息
     * @return array $msg
     */
    public function msg( array $msg = [] )
    {
        $this->msg = array_merge($this->msg, $msg);
        return $this->msg;
    }

    /**
     * 检查规则
     * @param  array $data  验证数据
     * @param  array $rules 验证规则
     * @param  array $msg   提示信息
     * @return void
     */
    public function check( array $data , array $rules = [] , array $msg = [] )
    {
        // 清空错误信息
        $this->error = '';
        // 是否使用传入的规则
        if (empty($rules)) {
            // 使用默认
            $rules = $this->rules;
        }
        // 是否使用传入的提示
        if (empty($msg)) {
            // 使用默认
            $msg = $this->msg;
        }
        // 读取差集
        $diff = array_diff_key($rules, $data);
        // 必传检查
        foreach ($diff as $dk => $dv) {
            // 是否必传
            if (stripos($dv, 'must') !== false) {

                $this->error = $this->check_item($dk, null, $dv, $msg);

                return false;
            }
        }
        // 只验证存在规则的数据
        $data = array_intersect_key($data, $rules);
        // 遍历验证数据
        foreach ($data as $key => $val) {
            // 验证规则
            $rule = $rules[$key];

            $result = $this->check_item($key, $val, $rule, $msg);
            // 只要没有返回true都是没有验证通过
            if ($result !== true) {

                $this->error = $result;

                return false;
            }
        }
        return true;
    }

    /**
     * 检查单个值是否符合规则
     * @param  string   $key    键值
     * @param  mixed    $value  验证的值
     * @param  mixed    $rule   验证规则
     * @param  array    $msg    提示信息
     * @return void
     */
    public function check_item( $key , $value , $rule , $msg )
    {
        // 是否有多个验证
        if (is_string($rule) && strpos($rule, '|') !== false) {
            $rule_arr = explode('|', $rule);
        } elseif (is_array($rule)) {
            $rule_arr = $rule;
        } else {
            $rule_arr[] = $rule;
        }

        // 执行验证
        foreach ($rule_arr as $item) {
            // 检查是否是闭包
            if ($item instanceof \Closure || is_callable($item)) {
                // 回调
                $result = call_user_func_array($item, [$key, $value]);
            } else {

                $array = [$key, $value];
                // 方法传参
                if (is_string($item) && strpos($item, ':') !== false) {
                    // 解析方法
                    [$item, $parstr] = explode(':', $item);
                    // 解析参数
                    $params = explode(',', $parstr);
                    // 合并参数
                    $array = array_merge($array, $params);
                }
                $result = call_user_func_array([$this, $item], $array);
            }

            // 只要没有返回true
            if ($result !== true) {

                $item = is_string($item) ? $item : '' ;
                // 检索错误信息
                if (array_key_exists($key .'.'. $item, $msg)) {
                    // 错误信息
                    $error = $msg[$key .'.'. $item];
                } elseif (array_key_exists($item, $msg)) {
                    // 错误信息
                    $error = $msg[$item];
                } else {
                    // 默认错误信息
                    $error = $key . ' does not conform to ' . $item . ' rules';
                }

                return empty($result) ? $error : $result ;
            }
        }
        
        return true;
    }

    /**
     * 验证必填信息
     * @param  string   $key    键值
     * @param  mixed    $val    验证的值
     * @return bool
     */
    public function must( $key , $val )
    {
        if (isset($val) && $val !== '') {
            return true;
        }
        return false;
    }

    /**
     * 获取错误信息
     * @return string $error 错误信息
     */
    public function error()
    {
        return $this->error;
    }

    /**
     * 访问不存在的方法
     * @return string $error 错误信息
     */
    public function __call( $method , $param )
    {
        return 'Validate method [' . $method . '] not exists';
    }
}